package cn.itsource.basic.service.impl;

import cn.itsource.basic.constant.WechatConstant;
import cn.itsource.basic.domain.LoginData;
import cn.itsource.basic.exception.CustomException;
import cn.itsource.basic.jwt.JwtUtils;
import cn.itsource.basic.jwt.RsaUtils;
import cn.itsource.basic.service.ILoginService;
import cn.itsource.basic.util.*;
import cn.itsource.org.domain.Logininfo;
import cn.itsource.org.domain.User;
import cn.itsource.org.domain.Wxuser;
import cn.itsource.org.domain.dto.UserSmsCodeDto;
import cn.itsource.org.domain.dto.WeChatBinderDto;
import cn.itsource.org.mapper.LogininfoMapper;
import cn.itsource.org.mapper.UserMapper;
import cn.itsource.org.mapper.WxuserMapper;
import cn.itsource.org.service.IUserService;
import cn.itsource.org.service.impl.UserServiceImpl;
import cn.itsource.system.domain.Menu;
import cn.itsource.system.mapper.MenuMapper;
import cn.itsource.system.mapper.PermissionMapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static cn.itsource.basic.jwt.JwtUtils.generateTokenExpireInMinutes;
import static cn.itsource.basic.jwt.JwtUtils.generateTokenExpireInSeconds;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserServiceImpl userService;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MenuMapper menuMapper;

    @Override
    public AjaxResult accountLogin(HashMap<String, Object> map){
        String userName = String.valueOf(map.get("username"));
        String password = String.valueOf(map.get("password"));
        Integer type = Integer.valueOf(map.get("type").toString());
        //查询账号是否存在记得判断用户类型
        Logininfo lf = logininfoMapper.loadByUserName(userName,type);
        if (lf == null){
            throw new CustomException("账号或密码错误!!");
        }
        //把前端传递的密码通过查询出的盐值加密后进行判断
        String salt = lf.getSalt();
        String oldPwd = lf.getPassword();
        String inputPwd = MD5Utils.encrypByMd5(password+salt);
        if(!oldPwd.equals(inputPwd)){
            throw new CustomException("账号或密码错误!!");
        }
//        //生成uuid作为token 存redis,存对象，对象需要序列化
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token,lf,30, TimeUnit.MINUTES);
//        //返回登录信息，返回token
//        HashMap<String, Object> resultMap = new HashMap<>();
//        resultMap.put("token",token);
//        //前端展示这些不安全
//        lf.setPassword(null);
//        lf.setSalt(null);
//        lf.setType(null);
//        resultMap.put("logininfo",lf);
//        return AjaxResult.me().setResultObj(resultMap);

        return loginsuccess(lf);
    }

    private AjaxResult loginsuccess(Logininfo lf) {
        HashMap<String, Object> resultMap = new HashMap<>();
        String token = "";
        //判断当前用户是门户站还是管理员，门户站只需要jsonwebtoken和logininfo
        if (lf.getType() == 1) {
            LoginData loginData = new LoginData(lf, null, null);
            //加密
            try {
                PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("hrm_auth_rsa").getFile());
                token = generateTokenExpireInMinutes(loginData, privateKey, 24*60);
            } catch (Exception e) {
                e.printStackTrace();
            }
            resultMap.put("logininfo", lf);
            resultMap.put("token",token);
        }else{
            //查询该用户的权限
            List<String> permissions = permissionMapper.loadPermissionSnByLoginInfoId(lf.getId());
            //查询该用户的菜单
            List<Menu> menus = menuMapper.loadMenusByLogininfoId(lf.getId());
            LoginData loginData = new LoginData(lf, permissions, menus);
            //生成jsonwebtoken
            //加密
            try {
                PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("hrm_auth_rsa").getFile());
                token = generateTokenExpireInMinutes(loginData, privateKey, 24*60);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //构建一个map，返回token，logininfo，menus，permissions
            resultMap.put("logininfo", lf);
            resultMap.put("menus",menus);
            resultMap.put("permissions",permissions);
            resultMap.put("token",token);
        }
        return AjaxResult.me().setResultObj(resultMap);
    }

    @Override
    public AjaxResult wechatLogin(HashMap<String, String> map) {
        //先接收到获取的code
        String code = map.get("code");
        //请求微信，获取用户的token和openid
        String url = WechatConstant.GET_TOKEN_URL
                .replace("APPID",WechatConstant.APPID)
                .replace("SECRET",WechatConstant.SECRET)
                .replace("CODE",code);
        //发请求获取结果
        String resultStr = HttpClientUtils.httpGet(url);
        //把请求结果的json字符串转成json对象
        JSONObject jo = JSON.parseObject(resultStr);
        //取出token和openid
        String access_token = jo.getString("access_token");
        String openid = jo.getString("openid");
        //查询openid对应的用户在我们平台是否已经存在
        Wxuser wxuser = wxuserMapper.loadByOpenid(openid);
        if(wxuser == null){
            //拼接token和openid返回给前端，前端跳转到绑定页面
            String binderUrl = "?token="+access_token+"&openid="+openid;
            return AjaxResult.me().setSuccess(false).setResultObj(binderUrl);
        }

        //免密登录
        Logininfo lf = logininfoMapper.loadByUserId(wxuser.getUserId());
//        //生成uuid作为token 存redis,存对象，对象需要序列化
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token,lf,30, TimeUnit.MINUTES);
//        //返回登录信息，返回token
//        HashMap<String, Object> resultMap = new HashMap<>();
//        resultMap.put("token",token);
//        //前端展示这些不安全
//        lf.setPassword(null);
//        lf.setSalt(null);
//        lf.setType(null);
//        resultMap.put("logininfo",lf);
//        return AjaxResult.me().setResultObj(resultMap);
        return loginsuccess(lf);
    }

    @Override
    public AjaxResult binder(WeChatBinderDto dto) {
        //把所有参数取出来
        String password = dto.getPassword();
        String accessToken = dto.getAccessToken();
        String openId = dto.getOpenId();
        String phone = dto.getPhone();
        //查询账号是否存在
        Logininfo lf = logininfoMapper.loadByUserName(phone, 1);
        //检查如果账号存在那么就终止业务
        if(lf != null){
            throw new CustomException("账号已存在!!!");
        }
        //发送请求获取用户的微信基本信息
        String url = WechatConstant.GET_WECHAT_INFO_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);

        String resultStr = HttpClientUtils.httpGet(url);

        JSONObject jo = JSON.parseObject(resultStr);

        //纯新号注册并关联微信基本信息
        //生成盐值
        String salt = StrUtils.getComplexRandomString(128);
        //加密后的密码
        String encrypPwd = MD5Utils.encrypByMd5(password + salt);

        UserSmsCodeDto smsDto = new UserSmsCodeDto();
        smsDto.setMobile(phone);

        //保存logininfo
        lf = userService.saveLoginInfo(smsDto, salt, encrypPwd);
        //保存user
        User user = userService.loginInfo2User(lf);
        //保存wxuser
        saveWxuser(openId, jo, user);

//        //免密登录
//        //生成uuid作为token 存redis,存对象，对象需要序列化
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token,lf,30, TimeUnit.MINUTES);
//        //返回登录信息，返回token
//        HashMap<String, Object> resultMap = new HashMap<>();
//        resultMap.put("token",token);
//        //前端展示这些不安全
//        lf.setPassword(null);
//        lf.setSalt(null);
//        lf.setType(null);
//        resultMap.put("logininfo",lf);
//        return AjaxResult.me().setResultObj(resultMap);
        return loginsuccess(lf);
    }

    private void saveWxuser(String openId, JSONObject jo, User user) {
        //保存wxuser
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(openId);
        wxuser.setNickname(jo.getString("nickname"));
        wxuser.setSex(jo.getInteger("sex"));
        wxuser.setAddress(jo.getString("country"));
        wxuser.setUnionid(jo.getString("unionid"));
        wxuser.setHeadimgurl(jo.getString("headimgurl"));
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);
    }


}
